home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
ms_sh21s.zip
/
SH210
/
SRC
/
SH4.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-14
|
39KB
|
1,835 lines
/* MS-DOS SHELL - 'word' Interpretator
*
* MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited and Charles Forsyth
*
* This code is based on (in part) the shell program written by Charles
* Forsyth and is subject to the following copyright restrictions:
*
* 1. Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in the
* source form and the copyright notice in file sh6.c is displayed
* on entry to the program.
*
* 2. The sources (or parts thereof) or objects generated from the sources
* (or parts of sources) cannot be sold under any circumstances.
*
* $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh4.c,v 2.4 1992/12/14 10:54:56 istewart Exp $
*
* $Log: sh4.c,v $
* Revision 2.4 1992/12/14 10:54:56 istewart
* BETA 215 Fixes and 2.1 Release
*
* Revision 2.3 1992/11/06 10:03:44 istewart
* 214 Beta test updates
*
* Revision 2.2 1992/09/03 18:54:45 istewart
* Beta 213 Updates
*
* Revision 2.1 1992/07/10 10:52:48 istewart
* 211 Beta updates
*
* Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson
* MS-Shell 2.0 Baseline release
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <limits.h> /* String library functions */
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#ifdef OS2
#define INCL_DOSSESMGR
#define INCL_DOSDEVICES
#include <os2.h> /* OS2 functions declarations */
#else
#include <dos.h>
#include <bios.h> /* DOS BIOS functions */
#endif
#include <malloc.h> /* Malloc functions */
#include <glob.h>
/* Special Addition to glob.h flags for the shell */
#define GLOB_CONVERT 0x0100 /* Convert file names */
#include "sh.h"
/*
* ${}, `command`, blank interpretation, quoting and file name expansion
*/
#define NSTART 16 /* default number of words to */
/* allow for initially */
static char *spcl = "[?*";
static char *_GP_MetaChars = "?*[\\";
static char *spcl1 = "\"'";
static char *bad_subs = "bad substitution\n";
static bool GlobbingInterrupted = FALSE;
/*
* Global variables for TWALK to build command environment
*/
static Word_B *BCE_WordList;
static int BCE_Length;
static bool near ExpandNames (char *, Word_B **, int);
static char near ExpandEnvironmentVariables (bool, int);
static bool near ExpandGravedCommand (bool, char);
static Word_B * near ExpandGlobbedName (char *, Word_B *, int);
static char * near blank (int);
static char * near unquote (char *, bool);
static Word_B * near CreateNewWordBlock (int);
static bool near CheckForReDirect (C_Op *, int);
static bool near ProcessVariable (char, bool);
static void BuildEnvironmentEntry (void *, VISIT, int);
static int near _GP_ExpandField (char *, char *, glob_t *);
static int near _GP_ExpandMetaCharacters (char *, glob_t *);
static int near _GP_StdargvAddArgument (char *, glob_t *);
static int near _GP_ShellAddArgument (char *, glob_t *);
static char * near _GP_CheckForMultipleDrives (char *);
static void _GP_HandleInterrupt (int);
static int near _GP_GetNumberofFloppyDrives (void);
static int (near * _GP_AddArgument) (char *, glob_t *) = _GP_StdargvAddArgument;
/*
* Expand all words to their full potential
*/
char **eval (register char **NameList, int ExpandMode,
struct ExecutableProcessing *PMode)
{
Word_B *wb = (Word_B *)NULL;
char **wp = (char **)NULL;
char **wf = (char **)NULL;
jmp_buf ev;
bool DecideProg = TRUE;
int Start;
/* Create a new IO environment */
if (CreateNewEnvironment (setjmp (ErrorReturnPoint = ev)) == FALSE)
{
while ((*NameList != (char *)NULL) && IsVariableAssignment (*NameList))
ExpandNames (*(NameList++), &wb, ExpandMode & ~EXPAND_GLOBBING);
if (FL_TEST ('k'))
{
for (wf = NameList; *wf != (char *)NULL; wf++)
{
if (IsVariableAssignment (*wf))
ExpandNames (*wf, &wb, ExpandMode & ~EXPAND_GLOBBING);
}
}
/* Now expand the words */
for (wb = AddWordToBlock ((char *)NULL, wb), Start = wb->w_nword;
*NameList; NameList++)
{
if (!FL_TEST ('k') || !IsVariableAssignment (*NameList))
ExpandNames (*NameList, &wb, ExpandMode & ~EXPAND_MOVE);
/* Get the program mode for expansion of words and globs */
if ((PMode != (struct ExecutableProcessing *)NULL) && DecideProg)
{
CheckProgramMode (wb->w_words[Start], PMode);
ExpandMode = (PMode->Flags & EP_NOEXPAND)
? EXPAND_ALL & ~EXPAND_GLOBBING : EXPAND_ALL;
if (PMode->Flags & EP_NOWORDS)
ExpandMode &= ~EXPAND_SPLITIFS;
if (PMode->Flags & EP_CONVERT)
ExpandMode |= EXPAND_CONVERT;
DecideProg = FALSE;
}
}
/* Get the word list */
wp = GetWordList (AddWordToBlock (NOWORD, wb));
QuitCurrentEnvironment ();
}
else
ExpansionErrorDetected = TRUE;
return ExpansionErrorDetected ? (char **)NULL : wp;
}
/*
* Make the exported environment from the exported names in the dictionary.
* Keyword assignments will already have been done. Convert to MSDOS
* format if flag set and m enabled
*/
char **BuildCommandEnvironment (void)
{
/* Update SECONDS and RANDOM */
HandleSECONDandRANDOM ();
/* Build the environment by walking the tree */
BCE_WordList = (Word_B *)NULL;
BCE_Length = 0;
twalk (VariableTree, BuildEnvironmentEntry);
if (BCE_Length >= 0x7f00)
return (char **)NULL;
return GetWordList (AddWordToBlock (NOWORD, BCE_WordList));
}
/*
* TWALK Function - Build Export VARIABLE list from VARIABLE tree
*/
static void BuildEnvironmentEntry (void *key, VISIT visit, int level)
{
VariableList *vp = *(VariableList **)key;
char *cp;
char *sp;
int tlen;
if ((visit != postorder) && (visit != leaf))
return;
if (vp->status & STATUS_EXPORT)
{
cp = GetVariableAsString (vp->name, TRUE);
tlen = strlen (vp->name) + strlen (cp) + 2;
if ((BCE_Length += tlen) >= 0x7f00)
return;
strcpy ((sp = GetAllocatedSpace (tlen)), vp->name);
SetMemoryAreaNumber ((void *)sp, MemoryAreaLevel);
strcat (sp, "=");
strcat (sp, cp);
BCE_WordList = AddWordToBlock (sp, BCE_WordList);
/* If MSDOS mode, we need to copy the variable, convert / to \ and put
* the copy in the environment list instead
*/
if ((FL_TEST ('m') || (ExecProcessingMode.Flags & EP_EXPORT)) &&
(vp->status & STATUS_CONVERT_MSDOS))
{
cp = StringCopy (BCE_WordList->w_words[BCE_WordList->w_nword - 1]);
BCE_WordList->w_words[BCE_WordList->w_nword - 1] = PATH_TO_DOS (cp);
}
}
}
/*
*
*/
char *evalstr (register char *cp, int ExpandMode)
{
Word_B *wb = (Word_B *)NULL;
/* Expand the name */
if (ExpandNames (cp, &wb, ExpandMode))
{
if ((wb == (Word_B *)NULL) || (wb->w_nword == 0) ||
((cp = wb->w_words[0]) == (char *)NULL))
cp = null;
ReleaseMemoryCell ((void *)wb);
}
else
cp = (char *)NULL;
return cp;
}
/* Expand special characters and variables */
static bool near ExpandNames (register char *cp, /* String to process */
register Word_B **wbp, /* Word block */
int ExpandMode) /* Expand mode */
{
jmp_buf ev;
char *IFS_Value = GetVariableAsString (IFS, FALSE);
ExpansionErrorDetected = FALSE;
if (cp == (char *)NULL)
return FALSE;
/* If there are no special characters and no separators, nothing to do,
* just save the word
*/
if (!anys (spcl2, cp) && !anys (IFS_Value, cp) &&
((ExpandMode & EXPAND_GLOBBING) == 0 || !anys (spcl, cp)))
{
cp = StringCopy (cp);
if (ExpandMode & DOTRIM)
unquote (cp, (bool)(ExpandMode & EXPAND_CONVERT));
*wbp = AddWordToBlock (cp, *wbp);
return TRUE;
}
/* Set up to read the word back in */
if (CreateNewEnvironment (setjmp (ErrorReturnPoint = ev)) == FALSE)
{
PUSHIO (aword, cp, String_GetNextCharacter, null);
e.iobase = e.iop;
while ((cp = blank (ExpandMode)) && !ExpansionErrorDetected)
{
e.linep = cp;
cp = StringCopy (cp);
/* Global expansion disabled ? */
if (((ExpandMode & EXPAND_GLOBBING) == 0) || FL_TEST ('f'))
{
if (ExpandMode & DOTRIM)
unquote (cp, (bool)(ExpandMode & EXPAND_CONVERT));
*wbp = AddWordToBlock (cp, *wbp);
}
else
*wbp = ExpandGlobbedName (cp, *wbp,
(ExpandMode & EXPAND_CONVERT)
? (GLOB_NOCHECK | GLOB_CONVERT) : GLOB_NOCHECK);
}
QuitCurrentEnvironment ();
}
else
ExpansionErrorDetected = TRUE;
return !ExpansionErrorDetected ? TRUE : FALSE;
}
/*
* Blank interpretation and quoting
*/
static char * near blank (int ExpandMode)
{
register int c, c1;
register char *sp = e.linep;
bool scanequals = (ExpandMode & EXPAND_MOVE) ? TRUE : FALSE;
bool foundequals = FALSE;
char *IFS_Value = GetVariableAsString (IFS, FALSE);
loop:
switch (c = subgetc (CHAR_DOUBLE_QUOTE, foundequals))
{
case 0:
if (sp == e.linep)
return (char *)NULL;
*(e.linep++) = 0;
return sp;
default:
if ((ExpandMode & EXPAND_SPLITIFS) && any ((char)c, IFS_Value))
goto loop;
break;
case CHAR_DOUBLE_QUOTE:
case CHAR_SINGLE_QUOTE:
scanequals = FALSE;
if (INSUB())
break;
for (c1 = c; (c = subgetc ((char)c1, TRUE)) != c1;)
{
if (c == 0)
break;
if ((c == CHAR_SINGLE_QUOTE) || !any ((char)c, "$`\""))
c |= QUOTE;
*(e.linep++) = (char)c;
}
c = 0;
}
ReturnGotCharacter (c);
if (!isalpha (c))
scanequals = FALSE;
while (1)
{
if (((c = subgetc (CHAR_DOUBLE_QUOTE, foundequals)) == 0) ||
(ExpandMode & EXPAND_SPLITIFS) &&
any ((char)c, IFS_Value) || !INSUB() && any ((char)c, spcl1))
{
scanequals = FALSE;
ReturnGotCharacter (c);
if (any ((char)c, spcl1))
goto loop;
break;
}
if (scanequals)
{
if (c == '=')
{
foundequals = TRUE;
scanequals = FALSE;
}
else if (!isalnum (c))
scanequals = FALSE;
}
*(e.linep++) = (char)c;
}
*(e.linep++) = 0;
return sp;
}
/*
* Get characters, substituting for ` and $
*/
int subgetc (register char ec, bool quoted)
{
register char c;
while (1)
{
c = (char)GetNextCharacter (ec);
if (!INSUB() && ec != CHAR_SINGLE_QUOTE)
{
/* Found a ` - execute the command */
if (c == CHAR_BACKQUOTE)
{
/* If both ec (end character) is zero and quoted flag is FALSE, this is execute
* command request is in a here document, so we have to collect the rest of
* the command from input. Otherwise, the command is in e.iop->argp->aword.
*
* We also need to set quoted so that CHAR_NEW_LINE are not processed when
* reading the output from the command.
*/
if (!ec && !quoted)
{
e.linep = e.cline;
if (CollectInputToCharacter (c, c) != 0)
return 0;
e.iop->argp->aword = e.cline + 1;
quoted = MAYBE;
}
if (ExpandGravedCommand (quoted, CHAR_BACKQUOTE) == 0)
return 0;
/* Re-read the character from the Grave function */
e.iop->TaskType = X_FROM_STDOUT;
}
/* $ - check for environment variable subsitution */
else if (c == '$')
{
if (!ProcessVariable (ec, quoted))
return 0;
}
/* No special processing required - return the character */
else
return c;
}
else
return c;
}
}
/*
* Handle $() in ${}
*/
static bool near ProcessVariable (char ec, bool quoted)
{
int c;
int passed = 0;
if ((c = GetNextCharacter (0)) == CHAR_OPEN_PARATHENSIS)
{
if ((passed = GetNextCharacter (0)) != CHAR_OPEN_PARATHENSIS)
{
/* If both ec (end character) is zero and quoted flag is FALSE, this is execute
* command request is in a here document, so we have to collect the rest of
* the command from input. Otherwise, the command is in e.iop->argp->aword.
*
* We also need to set quoted so that CHAR_NEW_LINE are not processed when
* reading the output from the command.
*/
if (!ec && !quoted)
{
e.linep = e.cline;
if (ScanForEndofWord (passed, SWT_STDOUT))
return 0;
e.iop->argp->aword = e.cline;
*(--e.linep) = CHAR_BACKQUOTE;
*(++e.linep) = 0;
quoted = MAYBE;
}
/* Replace the closing ) with a backquote. Remember that we've already
* absorbed a character, so remove it
*/
else
{
--(e.iop->argp->aword);
c = strlen (e.iop->argp->aword) - 2;
if (e.iop->argp->aword [c] != CHAR_CLOSE_PARATHENSIS)
c++;
e.iop->argp->aword [c] = CHAR_BACKQUOTE;
}
if (ExpandGravedCommand (quoted, CHAR_CLOSE_PARATHENSIS) == 0)
return FALSE;
/* Re-read the character from the Grave function */
e.iop->TaskType = X_FROM_STDOUT;
return TRUE;
}
/* OK - must be a $((...)) */
c = passed;
passed = CHAR_OPEN_PARATHENSIS;
}
/* Handle environment variable */
ReturnGotCharacter (c);
if ((c = ExpandEnvironmentVariables (quoted, passed)) == 0)
e.iop->TaskType = X_EXPAND_DOLLAR;
return TRUE;
}
/*
* Prepare to generate the string returned by ${} substitution.
*/
static char near ExpandEnvironmentVariables (bool quoted, int passed)
{
IO_State *oiop;
char *dolp, OriginalTaskType;
register char *s, c, *cp;
register char EndCharacter = 0;
char StartCharacter = 0;
bool colon_f = FALSE;
bool hash_f = FALSE;
char *dol_special = "$ ";
char DecimalString[12];
c = (char) (passed ? passed : ReadCharacterFromIOStack ());
s = e.linep;
/* Bracketed or not ? */
if ((c != CHAR_OPEN_BRACES) && (c != CHAR_OPEN_PARATHENSIS))
{
/* Get the string, while it is a alpha character */
*(e.linep++) = c;
if (isalpha (c))
{
while (((c = (char)ReadCharacterFromIOStack ()) != 0) &&
isalnum (c))
{
if (e.linep < e.eline)
*(e.linep++) = c;
}
ReturnGotCharacter (c);
}
c = 0;
}
/* Bracketed - special case */
else
{
oiop = e.iop;
OriginalTaskType = e.iop->TaskType;
e.iop->TaskType = X_ANYOTHER_IO;
StartCharacter = c;
EndCharacter = (char)((c == CHAR_OPEN_BRACES) ? CHAR_CLOSE_BRACES
: CHAR_CLOSE_PARATHENSIS);
if ((c == CHAR_OPEN_PARATHENSIS) &&
(subgetc (CHAR_DOUBLE_QUOTE, FALSE) != CHAR_OPEN_PARATHENSIS))
{
ShellErrorMessage ("missing ( in $((...))");
ExpansionErrorDetected = TRUE;
return c;
}
while (((c = (char)subgetc (CHAR_DOUBLE_QUOTE, FALSE)) != 0) &&
(c != CHAR_NEW_LINE))
{
if (c == EndCharacter)
{
if (EndCharacter == CHAR_CLOSE_BRACES)
break;
/* Found the end character ), check that it is followed by a second ) */
if (((c = (char)subgetc (CHAR_DOUBLE_QUOTE, FALSE)) == 0) ||
(c == CHAR_NEW_LINE) || (c == CHAR_CLOSE_PARATHENSIS))
break;
if (e.linep < e.eline)
*(e.linep++) = CHAR_CLOSE_PARATHENSIS;
}
if (e.linep < e.eline)
*(e.linep++) = c;
}
if (oiop == e.iop)
e.iop->TaskType = OriginalTaskType;
/* Check terminate correctly */
if (c != EndCharacter)
{
ShellErrorMessage ("unclosed $%c%c's", StartCharacter, EndCharacter);
ExpansionErrorDetected = TRUE;
return c;
}
/* Check for Hash at start */
if ((*s == '#') && (e.linep - s) > 1)
{
hash_f = TRUE;
memcpy (s, s + 1, e.linep - s - 1);
--e.linep;
}
/* Check for zero length string */
if (s == e.linep)
{
ShellErrorMessage (bad_subs);
ExpansionErrorDetected = TRUE;
return c;
}
}
/* Check line length */
if (e.linep >= e.eline)
{
ShellErrorMessage ("string in ${} too long");
ExpansionErrorDetected = TRUE;
e.linep -= 10;
}
*e.linep = 0;
/* Maths? */
if (EndCharacter == CHAR_CLOSE_PARATHENSIS)
{
sprintf (DecimalString, "%lu", EvaluateMathsExpression (s));
dolp = StringCopy (DecimalString);
e.linep = s;
PUSHIO (aword, dolp, quoted ? QuotedString_GetNextCharacter
: String_GetNextCharacter, null);
return 0;
}
/* Scan for =-+?%# in string */
if (*s)
{
for (cp = s + 1; *cp; cp++)
{
/* Check for end character other than null (=-+?) */
if (any (*cp, "=-+?%#"))
{
c = *cp;
/* Skip next section in case of % or #. Check for case of :[=-+?].
* If found - set flag
*/
if ((c != '%') && (c != '#') && (*(cp - 1) == ':'))
{
colon_f = TRUE;
*(cp - 1) = 0;
}
*(cp++) = 0;
break;
}
}
}
/* Cannot have both # & : */
if (hash_f && colon_f)
{
ShellErrorMessage (bad_subs);
ExpansionErrorDetected = TRUE;
return c;
}
/* Check for * and @ processing */
if (s[1] == 0 && (*s == '*' || *s == '@'))
{
if (ParameterCount > 1)
{
e.linep = s;
/* If hash flag set, convert to string length */
if (hash_f)
{
dolp = StringCopy (IntegerToString (ParameterCount - 1));
PUSHIO (aword, dolp, quoted ? QuotedString_GetNextCharacter
: String_GetNextCharacter, null);
}
else
{
PUSHIO (awordlist, ParameterArray + 1,
SpacedWordList_GetNextCharacter, null);
e.iop->StarAmpersandProcessing =
(char)(!quoted ? DSA_NULL : ((*s == '*') ? DSA_STAR
: DSA_AMP));
}
return 0;
}
/* trap the nasty ${=} */
else
{
s[0] = '1';
s[1] = 0;
}
}
/* Find the current value
*
* $~xxx variables are used by the Shell internally and cannot be accessed
* by the user.
*/
if (*s == '~')
dolp = null;
else if (!*s || !(isalnum (*s) || any (*s, "#-?$!")))
{
dol_special[1] = *s;
dolp = dol_special;
}
else if ((dolp = GetVariableAsString (s, TRUE)) == null)
{
switch (c)
{
case '=':
if (isdigit (*s))
{
ShellErrorMessage ("cannot use ${...=...} with $n");
ExpansionErrorDetected = TRUE;
break;
}
SetVariableFromString (s, cp);
dolp = GetVariableAsString (s, TRUE);
break;
case '-':
dolp = StringCopy (cp);
break;
case '?':
if (*cp == 0)
cp = "parameter null or not set";
ShellErrorMessage (BasicErrorMessage, s, cp);
ExpansionErrorDetected = TRUE;
break;
}
}
/* String exists - other processing */
else
{
char *pos; /* Position for substitute */
char *tsp;
int mode; /* Mode for substitute */
switch (c)
{
case '+':
dolp = StringCopy (cp);
break;
case '#': /* Remove prefix */
case '%': /* Remove suffix */
mode = GM_SHORTEST;
if (*cp == c)
{
mode = GM_LONGEST;
++cp;
}
if (c == '#')
{
if (GeneralPatternMatch (dolp, cp, FALSE, &pos, mode))
dolp = StringCopy (pos);
}
else if (SuffixPatternMatch (dolp, cp, &pos, mode))
{
tsp = StringCopy (dolp);
tsp[pos - dolp] = 0;
dolp = tsp;
}
break;
}
}
/* Check for unset values */
if (FL_TEST ('u') && dolp == null)
{
ShellErrorMessage ("unset variable %s\n", s);
ExpansionErrorDetected = TRUE;
}
/* If hash flag set, convert to string length */
if (hash_f)
dolp = StringCopy (IntegerToString (strlen (dolp)));
e.linep = s;
PUSHIO (aword, dolp, quoted ? QuotedString_GetNextCharacter
: String_GetNextCharacter, null);
return 0;
}
/*
* Run the command in `...` and read its output.
*/
static bool near ExpandGravedCommand (bool quoted, char End)
{
char *cp, *sp;
int localpipe, rv;
jmp_buf ev, rt;
C_Op *outtree;
Break_C bc;
int (*iof)(IO_State *);
/* Save area */
long s_flags = flags;
Word_B *s_wdlist = WordListBlock;
Word_B *s_iolist = IOActionBlock;
Break_C *S_RList = Return_List; /* Save loval links */
Break_C *S_BList = Break_List;
Break_C *S_SList = SShell_List;
int *s_fail = FailReturnPoint;
bool s_ProcessingEXECCommand = ProcessingEXECCommand;
FunctionList *s_CurrentFunction = CurrentFunction;
int Local_depth;
/* Check there is an ending grave */
if ((cp = strchr (e.iop->argp->aword, CHAR_BACKQUOTE)) == (char *)NULL)
{
ShellErrorMessage ("no closing %c", End);
return FALSE;
}
/* Create the pipe to read the output from the command string */
if ((localpipe = OpenAPipe ()) < 0)
{
ExpansionErrorDetected = TRUE;
return FALSE;
}
/* Terminate string and initialise save area */
*cp = 0;
/* Create a new environment */
S_dup2 (localpipe, 1);
FL_CLEAR ('e');
FL_CLEAR ('v');
FL_CLEAR ('n');
sp = StringCopy (e.iop->argp->aword);
MemoryAreaLevel++;
unquote (sp, FALSE);
/* Set up new environment */
Local_depth = Execute_stack_depth++;
rv = CreateGlobalVariableList (FLAGS_NONE);
if ((rv != -1) &&
(CreateNewEnvironment (setjmp (ErrorReturnPoint = ev)) == FALSE))
{
Return_List = (Break_C *)NULL;
Break_List = (Break_C *)NULL;
WordListBlock = (Word_B *)NULL;
IOActionBlock = (Word_B *)NULL;
PUSHIO (aword, sp, Line_GetNextCharacter, null);
e.cline = GetAllocatedSpace (LINE_MAX);
e.eline = e.cline + LINE_MAX - 5;
e.linep = e.cline;
e.iobase = e.iop;
/* Clear interrupt, error, AllowMultipleLines, InParse and execute flags. */
SW_intr = 0;
AllowMultipleLines = 0;
InParser = FALSE;
ProcessingEXECCommand = TRUE;
CurrentFunction = (FunctionList *)NULL;
/* Parse the line and execute it */
if ((setjmp (FailReturnPoint = rt) == 0) &&
((outtree = BuildParseTree ()) != (C_Op *)NULL))
{
/* Check for $(<..) construct */
if (CheckForReDirect (outtree, localpipe))
rv = 0;
else if (setjmp (bc.CurrentReturnPoint) == 0)
{
bc.NextExitLevel = SShell_List;
SShell_List = &bc;
rv = ExecuteParseTree (outtree, NOPIPE, NOPIPE, 0);
}
}
/* Parse error */
else
rv = -1;
/* Clean up any files around we nolonger need */
ClearExtendedLineFile ();
QuitCurrentEnvironment ();
}
else
rv = -1;
/* Fail - close pipe and delete it */
if (rv == -1)
{
S_Delete (localpipe);
S_close (localpipe, TRUE);
localpipe = -1;
}
/* Restore environment */
RestoreEnvironment (0, Local_depth);
/* Free old space */
FreeAllHereFiles (MemoryAreaLevel);
ReleaseMemoryArea (MemoryAreaLevel--); /* free old space */
/* Ok - completed processing - restore environment and read the pipe */
ProcessingEXECCommand = s_ProcessingEXECCommand;
flags = s_flags;
WordListBlock = s_wdlist;
IOActionBlock = s_iolist;
FailReturnPoint = s_fail;
Return_List = S_RList;
Break_List = S_BList;
SShell_List = S_SList;
CurrentFunction = s_CurrentFunction;
/* Move pipe to start so we can read it */
*(cp++) = CHAR_BACKQUOTE;
e.iop->argp->aword = cp;
if (localpipe == -1)
{
ExpansionErrorDetected = TRUE;
return FALSE;
}
lseek (localpipe, 0L, SEEK_SET);
iof = (!quoted) ? NonNLStdOut_GetNextCharacter
: ((quoted == MAYBE) ? NonQuoteSO_GetNextCharacter
: StdOut_GetNextCharacter);
PUSHIO (afile, ReMapIOHandler (localpipe), iof, null);
return TRUE;
}
/*
* Remove Quotes from a string
*/
static char *near unquote (register char *as, bool convert)
{
register char *s;
/* Unquote the string */
if ((s = as) == (char *)NULL)
return as;
while (*s)
*(s++) &= ~QUOTE;
/*
* Convert from UNIX to DOS format: Slashes to Backslashes in paths and
* dash to slash for switches
*/
if (convert)
{
if (*as == '-')
*as = '/';
else
PATH_TO_DOS (as);
}
return as;
}
/*
* Expand *, [] and ?
*/
static Word_B * near ExpandGlobbedName (char *cp, Word_B *wb, int mode)
{
int ReturnValue;
void (*sig_int)(int); /* Interrupt signal */
glob_t gp; /* Globbing structure */
/* Ignore null strings */
if (cp == (char *)NULL)
return wb;
/* We have to expand the word whilst any words in cp have special characters
* in them. First save the signal handler because I want to process
* signals differently in the glob function to allow us to use common code.
*/
GlobbingInterrupted = FALSE;
sig_int = signal (SIGINT, _GP_HandleInterrupt);
/* Expand the words */
e.GlobbingFileList = wb;
_GP_AddArgument = _GP_ShellAddArgument;
ReturnValue = glob (cp, mode, (int (*)())NULL , &gp);
/* Restore the signals */
signal (SIGINT, sig_int);
/* Check for abort */
if (GlobbingInterrupted)
raise (SIGINT);
/* Check for out of memory */
if (ReturnValue)
PrintErrorMessage (BasicErrorMessage, "sh", Outofmemory1);
/* Remove the NULL added by glob */
(e.GlobbingFileList)->w_nword--;
return e.GlobbingFileList;
}
/*
* Create a new Word Block
*/
static Word_B * near CreateNewWordBlock (register int nw)
{
register Word_B *wb;
if ((wb = (Word_B *)
GetAllocatedSpace (sizeof (Word_B) + nw * sizeof (char *)))
!= (Word_B *)NULL)
{
wb->w_bsize = nw;
wb->w_nword = 0;
}
return wb;
}
/*
* Add a new word to a Word Block or list
*/
Word_B *AddWordToBlock (char *wd, register Word_B *wb)
{
register Word_B *wb2;
register int nw;
if (wb == (Word_B *)NULL)
wb = CreateNewWordBlock (NSTART);
if (wb == (Word_B *)NULL)
return (Word_B *)NULL;
/* Do we require more space ? */
if ((nw = wb->w_nword) >= wb->w_bsize)
{
if ((wb2 = CreateNewWordBlock (nw * 2)) == (Word_B *)NULL)
return (Word_B *)NULL;
memcpy ((void *)wb2->w_words, (void *)wb->w_words,
nw * sizeof (void *));
wb2->w_nword = nw;
ReleaseMemoryCell ((void *)wb);
wb = wb2;
}
/* Add to the list */
wb->w_words[wb->w_nword++] = wd;
return wb;
}
/*
* Convert a word block structure into a array of strings
*/
char **GetWordList (register Word_B *wb)
{
register char **wd;
register int nb;
/* If the word block is empty or does not exist, return no list */
if (wb == (Word_B *)NULL)
return (char *)NULL;
/* Get some space for the array and set it up */
if (((nb = sizeof (char *) * wb->w_nword) == 0) ||
((wd = (char **)GetAllocatedSpace (nb)) == (char **)NULL))
{
ReleaseMemoryCell ((void *)wb);
return (char *)NULL;
}
memcpy ((char *)wd, (char *)wb->w_words, nb);
ReleaseMemoryCell ((void *)wb); /* perhaps should done by caller */
return wd;
}
/*
* Is any character from s1 in s2? Return a boolean.
*/
bool anys (register char *s1, register char *s2)
{
while (*s1)
{
if (any (*(s1++), s2))
return TRUE;
}
return FALSE;
}
/*
* Special version of glob.c for the shell. A bit stripped down, since
* neither the shell or stdargv.c use some of the functionality.
*/
/* Free up space */
void globfree (glob_t *gp)
{
int i = 0;
while (i < gp->gl_pathc)
free (gp->gl_pathv[i++]);
free (gp->gl_pathv);
}
/* Main search function */
int glob (char *Pattern, int flags, int (*ErrorFunction) (char *, int), glob_t *gp)
{
int ReturnValue;
char *PatternCopy;
char *cp;
/* If no append mode - initialise */
gp->gl_pathc = 0;
gp->gl_pathv = (char **)NULL;
gp->gl_flags = flags;
gp->gl_ef = ErrorFunction;
if ((PatternCopy = alloca (strlen (Pattern) + 1)) == (char *)NULL)
return GLOB_NOSPACE;
/* Expand and kill environment */
if (ReturnValue = _GP_ExpandMetaCharacters (strcpy (PatternCopy, Pattern),
gp))
return ReturnValue;
/* Check for no finds. If add value, strip out \ from the string */
if (gp->gl_pathc == 0)
{
cp = strcpy (PatternCopy, Pattern);
while ((cp = strpbrk (cp, "?*[")) != (char *)NULL)
{
if ((cp == PatternCopy) || (*(cp - 1) != '\\'))
cp++;
else
memmove (cp - 1, cp, strlen (cp) + 1);
}
if (ReturnValue = (*_GP_AddArgument) (PatternCopy, gp))
return ReturnValue;
}
/* Terminate string */
if ((gp->gl_pathc != 0) &&
(ReturnValue = (*_GP_AddArgument) ((char *)NULL, gp)))
return ReturnValue;
/* Get the sort length */
if (gp->gl_pathc > 1)
qsort (&gp->gl_pathv[0], gp->gl_pathc, sizeof (char *), _GP_SortCompare);
return 0;
}
/* Compare function for sort */
int _GP_SortCompare (char **a1, char **a2)
{
return strcmp (*a1, *a2);
}
/* Expand a field if it has metacharacters in it */
static int near _GP_ExpandField (char *CurrentDirectoryPattern,
char *AppendString, glob_t *gp)
{
int i;
int ReturnValue = 0; /* Return Value */
char *FullFileName; /* Search file name */
char *FileNameStart;
char *MatchString; /* Match string */
DIR *DirHandler;
struct dirent *CurrentDirectoryEntry;
unsigned int CurrentDrive; /* Current drive */
unsigned int MaxDrives; /* Max drive */
unsigned int SelectedDrive; /* Selected drive */
unsigned int y_drive; /* Dummies */
char *DriveCharacter; /* Multi-drive flag */
char SDriveString[2];
bool IgnoreCase = TRUE;
/* Globbing interrupted ? */
if (GlobbingInterrupted)
return GLOB_ABEND;
/* Convert file name to lower case */
#ifndef OS2
strlwr (CurrentDirectoryPattern);
#else
if (!IsHPFSFileSystem (CurrentDirectoryPattern))
strlwr (CurrentDirectoryPattern);
else
IgnoreCase = FALSE;
#endif
/* Search all drives ? */
if ((DriveCharacter = _GP_CheckForMultipleDrives (CurrentDirectoryPattern))
!= (char *)NULL)
{
CurrentDrive = GetCurrentDrive ();
MaxDrives = SetCurrentDrive (CurrentDrive);
SDriveString[1] = 0;
for (SelectedDrive = 1; SelectedDrive <= MaxDrives; ++SelectedDrive)
{
SetCurrentDrive (SelectedDrive);
y_drive = GetCurrentDrive ();
SetCurrentDrive (CurrentDrive);
/* Check to see if the second diskette drive is really there */
if ((_GP_GetNumberofFloppyDrives () < 2) && (SelectedDrive == 2))
continue;
/* If the drive exists and is in our list - process it */
*DriveCharacter = 0;
*SDriveString = (char)(SelectedDrive + 'a' - 1);
strlwr (CurrentDirectoryPattern);
if ((y_drive == SelectedDrive) &&
GeneralPatternMatch (SDriveString, CurrentDirectoryPattern,
TRUE, (char **)NULL, GM_ALL))
{
if ((FullFileName = alloca (strlen (DriveCharacter) + 3))
== (char *)NULL)
return GLOB_NOSPACE;
*DriveCharacter = ':';
*FullFileName = *SDriveString;
strcpy (FullFileName + 1, DriveCharacter);
if (i = _GP_ExpandField (FullFileName, AppendString, gp))
return i;
}
*DriveCharacter = ':';
}
return 0;
}
/* Get the path length */
if (((MatchString = strrchr (CurrentDirectoryPattern,
CHAR_UNIX_DIRECTORY)) == (char *)NULL)
&& (*(CurrentDirectoryPattern + 1) == ':'))
MatchString = CurrentDirectoryPattern + 1;
/* Set up file name for search */
if ((MatchString == (char *)NULL) || (*MatchString == ':'))
{
if ((FullFileName = alloca (NAME_MAX + 7 +
strlen (AppendString))) == (char *)NULL)
return GLOB_NOSPACE;
if (MatchString != (char *)NULL)
*(strcpy (FullFileName, "x:.")) = *CurrentDirectoryPattern;
else
strcpy (FullFileName, ".");
FileNameStart = FullFileName +
(int)((MatchString != (char *)NULL) ? 2 : 0);
}
/* Case of /<directory>/... */
else if ((FullFileName = alloca (NAME_MAX + 4 + strlen (AppendString) +
(i = (int)(MatchString - CurrentDirectoryPattern))))
== (char *)NULL)
return GLOB_NOSPACE;
else
{
strncpy (FullFileName, CurrentDirectoryPattern, i);
*((FileNameStart = FullFileName + i)) = 0;
strcpy (FileNameStart++, DirectorySeparator);
}
MatchString = (MatchString == (char *)NULL) ? CurrentDirectoryPattern
: MatchString + 1;
/* Search for file names */
if ((DirHandler = opendir (CheckDOSFileName (FullFileName))) == (DIR *)NULL)
return 0;
/* Are there any matches */
while ((CurrentDirectoryEntry = readdir (DirHandler)) !=
(struct dirent *)NULL)
{
/* Globbing interrupted ? */
if (GlobbingInterrupted)
{
ReturnValue = GLOB_ABEND;
break;
}
/* Ignore . files? */
if ((*CurrentDirectoryEntry->d_name == '.') && (*MatchString != '.'))
continue;
/* Check for match */
if (GeneralPatternMatch (CurrentDirectoryEntry->d_name, MatchString,
IgnoreCase, (char **)NULL, GM_ALL))
{
strcpy (FileNameStart, CurrentDirectoryEntry->d_name);
/* If the postfix is not null, this must be a directory */
if (strlen (AppendString))
{
char *p;
/* If not a directory - go to the next file */
if (!IsDirectory (FullFileName))
continue;
/* Are there any metacharacters in the postfix? */
if ((p = strpbrk (AppendString, _GP_MetaChars)) == (char *)NULL)
{
/* No - build the file name and check it exists */
strcat (strcat (FileNameStart, DirectorySeparator),
AppendString);
if ((access (CheckDOSFileName (FullFileName), F_OK) == 0) &&
(ReturnValue = (*_GP_AddArgument) (FullFileName, gp)))
break;
}
/* Yes - build the filename upto the start of the meta characters */
else
{
if ((p = strchr (p, CHAR_UNIX_DIRECTORY)) != (char *)NULL)
*(p++) = 0;
else
p = null;
/* Build the new directory name and check it out */
strcat (strcat (FileNameStart, DirectorySeparator),
AppendString);
ReturnValue = _GP_ExpandField (FullFileName, p, gp);
if (p != null)
*(--p) = CHAR_UNIX_DIRECTORY;
/* Check for errors */
if (ReturnValue)
break;
}
}
/* Process this file. If error - terminate */
else if ((access (CheckDOSFileName (FullFileName), F_OK) == 0) &&
(ReturnValue = (*_GP_AddArgument) (FullFileName, gp)))
break;
}
}
closedir (DirHandler);
return ReturnValue;
}
/* Find the location of meta-characters. If no meta, add the argument and
* return. If meta characters, expand directory containing meta characters.
*/
static int near _GP_ExpandMetaCharacters (char *file, glob_t *gp)
{
char *p;
int ReturnValue;
/* Globbing interrupted ? */
if (GlobbingInterrupted)
return GLOB_ABEND;
/* No metas - add to string */
if ((p = strpbrk (file, _GP_MetaChars)) == (char *)NULL)
{
if (access (CheckDOSFileName (file), F_OK) < 0)
return 0;
return (*_GP_AddArgument) (file, gp);
}
/* Ok - metas, find the end of the start of the directory */
else if ((p = strchr (p, CHAR_UNIX_DIRECTORY)) != (char *)NULL)
*(p++) = 0;
else
p = null;
/* Continue recusive match */
ReturnValue = _GP_ExpandField (file, p, gp);
/* Restore if necessary */
if (p != null)
*(--p) = CHAR_UNIX_DIRECTORY;
return ReturnValue;
}
/* Check for multi_drive prefix */
static char * near _GP_CheckForMultipleDrives (char *prefix)
{
if (strlen (prefix) < 2)
return (char *)NULL;
if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
return prefix + 1;
if (*prefix != CHAR_OPEN_BRACKETS)
return (char *)NULL;
while (*prefix && (*prefix != CHAR_CLOSE_BRACKETS))
{
if ((*prefix == '\\') && (*(prefix + 1)))
++prefix;
++prefix;
}
return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
}
/*
* Stdargv version of AddArgument
*
* Add an argument to the stack - file is assumed to be a array big enough
* for the file name + 2
*/
static int near _GP_StdargvAddArgument (char *file, glob_t *gp)
{
size_t Offset = (gp->gl_pathc + 50) * sizeof (char *);
/* Malloc space if necessary */
if (gp->gl_pathc == 0)
gp->gl_pathv = (char **)malloc (Offset);
else if ((gp->gl_pathc % 50) == 0)
gp->gl_pathv = (char **)realloc (gp->gl_pathv, Offset);
if (gp->gl_pathv == (char **)NULL)
return GLOB_NOSPACE;
/* OK got space, check for End of list ? */
if (file == (char *)NULL)
gp->gl_pathv[gp->gl_pathc] = (char *)NULL;
else if ((gp->gl_pathv[gp->gl_pathc++] = strdup (file)) == (char *)NULL)
return GLOB_NOSPACE;
return 0;
}
/*
* Shell version of AddArgument
*
* Add an argument to the stack - file is assumed to be a array big enough
* for the file name + 2
*/
static int near _GP_ShellAddArgument (char *file, glob_t *gp)
{
Word_B *wb2, *wb;
char *CopyFN = (char *)NULL;
int nw;
static int StartOffset = 0;
if (GlobbingInterrupted)
return GLOB_ABEND;
if ((wb = e.GlobbingFileList) == (Word_B *)NULL)
wb = CreateNewWordBlock (NSTART);
if (wb == (Word_B *)NULL)
return GLOB_NOSPACE;
/* Do we require more space ? */
if ((nw = wb->w_nword) >= wb->w_bsize)
{
if ((wb2 = CreateNewWordBlock (nw * 2)) == (Word_B *)NULL)
return GLOB_NOSPACE;
memcpy ((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
wb2->w_nword = nw;
ReleaseMemoryCell ((void *)wb);
wb = wb2;
}
/* If the first time through for this expansion, save the start of
* expansion address
*/
if (!gp->gl_pathc)
StartOffset = nw;
/* Add to the list */
if (file != (char *)NULL)
{
if ((CopyFN = AllocateMemoryCell (strlen (file) + 2)) == (char *)NULL)
return GLOB_NOSPACE;
strcpy (CopyFN, file);
/* Mark directory entries? */
if ((GlobalFlags & FLAGS_MARKDIRECTORY) &&
IsDirectory (CopyFN))
strcat (CopyFN, "/");
++(gp->gl_pathc);
}
unquote (CopyFN, (bool)(gp->gl_flags & GLOB_CONVERT));
(e.GlobbingFileList = wb)->w_words[wb->w_nword++] = CopyFN;
gp->gl_pathv = &wb->w_words[StartOffset];
return 0;
}
/*
* Handle interrupt signals during globbing
*/
static void _GP_HandleInterrupt (int signo)
{
signal (signo, _GP_HandleInterrupt);
GlobbingInterrupted = TRUE;
}
/* Return the number of floppy disks */
static int near _GP_GetNumberofFloppyDrives (void)
{
#ifdef OS2
BYTE nflop = 1;
DosDevConfig (&nflop, DEVINFO_FLOPPY, 0);
return nflop;
#else
return ((_bios_equiplist () & 0x00c0) >> 6) + 1;
#endif
}
/*
* Build up the parameter variables
*/
Word_B *AddParameter (char *value, Word_B *wb, char *function)
{
char **NewArray;
int Count;
int i;
/* Add to block */
if ((wb = AddWordToBlock (value, wb)) == (Word_B *)NULL)
{
fprintf (stderr, BasicErrorMessage, function, Outofmemory1);
return (Word_B *)NULL;
}
/* If not end, return */
if (value != (char *)NULL)
return wb;
/* Get number of entries */
Count = wb->w_nword - 1;
/* Convert to array */
if ((NewArray = GetWordList (wb)) == (char **)NULL)
{
fprintf (stderr, BasicErrorMessage, function, Outofmemory1);
return (Word_B *)NULL;
}
/* Release old array. Note: never release entry zero */
if (ParameterArray != (char **)NULL)
{
for (i = 1; i < ParameterCount; ++i)
ReleaseMemoryCell ((void *)ParameterArray [i]);
ReleaseMemoryCell ((void *)ParameterArray);
}
/* Set new array to no-release */
for (i = 0; i < Count; ++i)
SetMemoryAreaNumber ((void *)NewArray[i], 0);
SetMemoryAreaNumber ((void *)NewArray, 0);
/* Reset globals and environment */
ParameterCount = Count - 1;
ParameterArray = NewArray;
SetVariableFromNumeric (ParameterCountVariable, (long)ParameterCount);
return wb;
}
/*
* Check for assignment X=Y
*/
bool IsVariableAssignment (register char *s)
{
return (IsValidVariableName (s) == '=') ? TRUE : FALSE;
}
/*
* Is this a valid variable name
*/
char IsValidVariableName (register char *s)
{
if (!isalpha (*s))
return *s;
while (*s && isalnum (*s))
++s;
return *s;
}
/*
* Check for $(<...) construct
*/
static bool near CheckForReDirect (C_Op *t, int fp_pipe)
{
IO_Actions **iopp = t->ioact;
if ((t->type != TCOM) || (*t->words != (char *)NULL) ||
(iopp == (IO_Actions **)NULL))
return FALSE;
/* Look for the stdin selection */
while (*iopp != (IO_Actions *)NULL)
{
if (((*iopp)->io_unit == IODEFAULT) &&
((*iopp)->io_flag & (IOREAD | IOHERE)))
{
(*iopp)->io_unit = fp_pipe;
SetUpIOHandlers (*iopp, -1, -1);
return TRUE;
}
iopp++;
}
return FALSE;
}